package cn.aitrox.ry.service.user.service.impl;

import cn.aitrox.ry.bean.CommonPageInfo;
import cn.aitrox.ry.bean.JwtTokenCheckResult;
import cn.aitrox.ry.bean.RespResult;
import cn.aitrox.ry.common.bean.Order;
import cn.aitrox.ry.common.dao.MapperSqlCallback;
import cn.aitrox.ry.common.service.api.dto.Company;
import cn.aitrox.ry.common.service.api.dto.User;
import cn.aitrox.ry.enumtype.RespCodeEnum;
import cn.aitrox.ry.service.user.config.NacosProp;
import cn.aitrox.ry.service.user.dao.CompanyDao;
import cn.aitrox.ry.service.user.dao.UserDao;
import cn.aitrox.ry.service.user.ennumtype.UserStatusEnum;
import cn.aitrox.ry.service.user.entity.CompanyEntity;
import cn.aitrox.ry.service.user.entity.UserEntity;
import cn.aitrox.ry.service.user.po.UserCountParamPo;
import cn.aitrox.ry.service.user.po.UserFindParamPo;
import cn.aitrox.ry.service.user.service.UserService;
import cn.aitrox.ry.util.ArrayUtil;
import cn.aitrox.ry.util.BeanUtil;
import cn.aitrox.ry.util.CodeUtil;
import cn.aitrox.ry.util.JwtUtils;
import cn.aitrox.ry.util.ObjectUtil;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RefreshScope
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private NacosProp nacosProp;

    @Autowired
    private UserDao userDao;

    @Autowired
    private CompanyDao companyDao;

    @Transactional
    @Override
    public void create(String userName, String mobile, Integer companyId) {
        UserEntity userEntity = new UserEntity(null, CodeUtil.genShortCode(8), userName.trim(), mobile.trim(), nacosProp.getUserDefaultPwd(), UserStatusEnum.ENABLE.getStatus(), companyId);
        userDao.insertSelective(userEntity);
    }

    @Override
    public CommonPageInfo<User> search(Integer page, Integer pageSize, String keyword, Integer companyId, Integer status) {
        String likeKeyword = null;
        if (null != keyword) {
            likeKeyword = "%" + keyword + "%";
        }

        UserFindParamPo param = new UserFindParamPo(likeKeyword, companyId, status);
        PageInfo<UserEntity> pageInfo = userDao.searchByCustom(page, pageSize, Order.desc("id"), new MapperSqlCallback<UserEntity>() {
            @Override
            public List<UserEntity> invoke() {
                return userDao.findByCustom(param);
            }
        });

        if (ArrayUtil.isEmpty(pageInfo.getList())) {
            return new CommonPageInfo();
        }

        List<CompanyEntity> companyList = companyDao.findAll();
        Map<Integer, CompanyEntity> companyMap = companyList.stream().collect(Collectors.toMap(CompanyEntity::getId, x -> x));

        List<User> userList = pageInfo.getList().stream().map(x -> {
            return packUser(x, companyMap.get(x.getCompanyId()), null);
        }).collect(Collectors.toList());

        return new CommonPageInfo<>(pageInfo.getTotal(), pageInfo.getPages(), userList);
    }

    @Transactional
    @Override
    public void edit(Integer id, String userName, String mobile, String pwd, Integer companyId, Integer status) {
        UserEntity userEntity = new UserEntity(id, null, userName, mobile, pwd, status, companyId);
        userDao.updateByIdSelective(userEntity);
    }

    @Override
    public RespResult<User> login(String mobile, String pwd) {
        UserEntity cond = new UserEntity();
        cond.setMobile(mobile);
        cond.setPwd(pwd);
        UserEntity userEntity = userDao.findOne(cond);
        if (null == userEntity) {
            return RespResult.error("用户名或密码错误");
        }
        CompanyEntity companyEntity = companyDao.findById(userEntity.getCompanyId());

        User user = packUser(userEntity, companyEntity, null);

        // 生成token
        String token = JwtUtils.genToken(nacosProp.getTokenSecret(), nacosProp.getLoginExpireSeconds(), user);
        if (null == token) {
            return RespResult.error("生成Token失败");
        }

        user.setToken(token);

        return RespResult.ok(user);
    }

    @Override
    public UserEntity findById(Integer id) {
        return userDao.findById(id);
    }

    @Override
    public List<User> list(List<Integer> ids) {
        if (ArrayUtil.isEmpty(ids)) {
            return new ArrayList<>();
        }
        List<UserEntity> userList = userDao.findByIds(ids.toArray(), null);
        if (ArrayUtil.isEmpty(userList)) {
            return new ArrayList<>();
        }

        List<CompanyEntity> companyList = companyDao.findAll();
        Map<Integer, CompanyEntity> companyMap = companyList.stream().collect(Collectors.toMap(CompanyEntity::getId, x -> x));

        return userList.stream().map(x -> {
            return packUser(x, companyMap.get(x.getCompanyId()), null);
        }).collect(Collectors.toList());
    }

    @Override
    public Integer count(List<Integer> companyIds, Integer status) {
        return userDao.countByCond(new UserCountParamPo(companyIds, status));
    }

    @Override
    public JwtTokenCheckResult<User> tokenAuth(String token) {
        JwtTokenCheckResult<User> checkResult = JwtUtils.checkToken(nacosProp.getTokenSecret(), token, User.class);
        if (checkResult.success()) {
            // 校验用户状态
            Integer userId = checkResult.getCustomPayload().getId();
            UserEntity userEntity = userDao.findById(userId);
            if (null == userEntity || !UserStatusEnum.ENABLE.getStatus().equals(userEntity.getStatus())) {
                checkResult.setRespCodeEnum(RespCodeEnum.NO_PERMISSION);
                return checkResult;
            }

            // 判断过期时间剩余，如果剩余过期时间小于30分钟，颁发新token
            Date expiresAt = checkResult.getExpiresAt();
            Date now = new Date();
            int remainSeconds = ((Long) ((expiresAt.getTime() - now.getTime()) / 1000)).intValue();
            if (remainSeconds <= nacosProp.getRenewalRemainSeconds()) {
                Map<String, Object> customPayload = ObjectUtil.obj2Map(checkResult.getCustomPayload());
                // 生成token
                String newToken = JwtUtils.genToken(nacosProp.getTokenSecret(), nacosProp.getLoginExpireSeconds(), customPayload);
                checkResult.getCustomPayload().setToken(newToken);
            } else {
                checkResult.getCustomPayload().setToken(token);
            }
        }
        return checkResult;
    }

    @Override
    public RespResult<User> read(Integer id) {
        UserEntity userEntity = userDao.findById(id);
        if (null == userEntity) {
            return RespResult.secByError(RespCodeEnum.NOT_EXIST.getCode(), "用户不存在");
        }
        CompanyEntity companyEntity = null;
        if (null != userEntity.getCompanyId()) {
            companyEntity = companyDao.findById(userEntity.getCompanyId());
        }
        User user = packUser(userEntity, companyEntity, null);
        return RespResult.ok(user);
    }

    @Override
    public UserEntity findByMobile(String mobile) {
        if (null == mobile) {
            return null;
        }
        UserEntity cond = new UserEntity();
        cond.setMobile(mobile);
        return userDao.findOne(cond);
    }

    private User packUser(UserEntity userEntity, CompanyEntity companyEntity, String token) {
        User user = new User();
        BeanUtil.copy(userEntity, user);
        if (null != companyEntity) {
            Company company = new Company();
            BeanUtil.copy(companyEntity, company);
            user.setCompany(company);
        }
        user.setToken(token);
        return user;
    }
}
